package org.su.mamamiya.swagger.processor;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.List;
import lombok.Data;
import org.su.mamamiya.core.ast.AstProccessor;
import org.su.mamamiya.core.ast.DocHelper;
import org.su.mamamiya.core.ast.Logger;
import org.su.mamamiya.core.ast.ParamDoc;
import org.su.mamamiya.swagger.annotation.Swagger;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import java.util.Set;


/**
 * Created by yangchuan on 2019-10-02 15:37
 */
@SupportedAnnotationTypes({"org.su.mamamiya.swagger.annotation.Swagger","lombok.Data"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class JopoProccessor extends AbstractProcessor {

    private AstProccessor astProccessor;
    private DocHelper docHelper;
    private Logger logger;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        logger = new Logger(processingEnv.getMessager());

        astProccessor = new AstProccessor(processingEnv);
        docHelper = new DocHelper(astProccessor);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Swagger.class);
        process(roundEnv,elements);
        elements = roundEnv.getElementsAnnotatedWith(Data.class);
        process(roundEnv,elements);
        return true;
    }

    private void process( RoundEnvironment roundEnv,Set<? extends Element> elements){
        JCTree t = null;
        for (Element element : elements) {
            if (element.getKind() != ElementKind.CLASS) {
                logger.error(String.format("Only class can be annotated with @%s", Swagger.class.getSimpleName()));
                return;
            }
            t = astProccessor.getTree(element);
            t.accept(new TreeTranslator() {
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    List<JCTree.JCExpression> expressions = List.nil();
                    JCTree.JCAnnotation jcAnnotation = astProccessor.getAnnotation(astProccessor.memberAccess("io.swagger.annotations.ApiModel"), expressions);

                    JCTree.JCModifiers jcModifiers = jcClassDecl.getModifiers();
                    jcModifiers.annotations = jcModifiers.annotations.append(jcAnnotation);
                    jcClassDecl.mods = jcModifiers;

                    jcClassDecl.defs.stream().filter(k -> k.getKind().equals(Tree.Kind.VARIABLE)).map(tree -> (JCTree.JCVariableDecl) tree).forEach(jcVariableDecl -> {
                        JCTree.JCModifiers jcFModifiers = jcVariableDecl.getModifiers();

                        String txt = docHelper.getFiledDoc(element, jcVariableDecl.getName().toString());
                        ParamDoc paramDoc = docHelper.getParamDoc(txt);
                        List<JCTree.JCExpression> fexpressions = List.nil();

                        fexpressions = fexpressions.append(astProccessor.assign("value", paramDoc.getMark()))
                                .append(astProccessor.assign("required", paramDoc.isNotNull()));
                        if (paramDoc.isReaded()) {
                            fexpressions = fexpressions.append(astProccessor.assign("readOnly", paramDoc.isReaded()));
                            //fexpressions = fexpressions.append(treeMaker.Assign(treeMaker.Ident(names.fromString("accessMode")), treeMaker.Literal(TypeTag.DEFERRED,ApiModelProperty.AccessMode.READ_ONLY)));
                        }

                        JCTree.JCAnnotation jcFAnnotation = astProccessor.getAnnotation(astProccessor.memberAccess("io.swagger.annotations.ApiModelProperty"), fexpressions);
                        jcFModifiers.annotations = jcFModifiers.annotations.append(jcFAnnotation);

                        jcVariableDecl.mods = jcFModifiers;

                    });
                    super.visitClassDef(jcClassDecl);
                }
            });
        }
    }


}
